/*
 * Copyright (c) 2002 - 2016 IBM Corporation.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     Brian Pfretzschner - initial implementation
 */
package com.ibm.wala.cast.js.nodejs;

import com.ibm.wala.cast.ipa.callgraph.CAstCallGraphUtil;
import com.ibm.wala.classLoader.SourceFileModule;
import com.ibm.wala.util.collections.HashMapFactory;
import com.ibm.wala.util.collections.HashSetFactory;
import com.ibm.wala.util.io.TemporaryFile;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.util.Map;
import java.util.Set;
import org.apache.commons.io.FilenameUtils;

/**
 * @author Brian Pfretzschner &lt;brian.pfretzschner@gmail.com&gt;
 */
public class NodejsRequiredCoreModule extends NodejsRequiredSourceModule {

  /**
   * Core modules list for Nodejs v6.2.2
   *
   * @see <a href="https://github.com/nodejs/node/blob/v6.2.2/lib/internal/module.js">module.js</a>
   */
  private static final Set<String> CORE_MODULES =
      HashSetFactory.of(
          "assert",
          "buffer",
          "child_process",
          "cluster",
          "crypto",
          "dgram",
          "dns",
          "domain",
          "events",
          "fs",
          "http",
          "https",
          "net",
          "os",
          "path",
          "punycode",
          "querystring",
          "readline",
          "repl",
          "stream",
          "string_decoder",
          "tls",
          "tty",
          "url",
          "util",
          "v8",
          "vm",
          "zlib",

          // Non-public files
          "timers",
          "constants",
          "freelist",
          "smalloc",
          "_debugger",
          "_http_agent",
          "_http_client",
          "_http_common",
          "_http_incoming",
          "_http_outgoing",
          "_http_server",
          "_linklist",
          "_stream_duplex",
          "_stream_passthrough",
          "_stream_readable",
          "_stream_transform",
          "_stream_writable",
          "_tls_common",
          "_tls_legacy",
          "_tls_wrap");

  protected NodejsRequiredCoreModule(File f, SourceFileModule clonedFrom) throws IOException {
    super(FilenameUtils.getBaseName(f.getName()), f, clonedFrom);
  }

  private static InputStream getModule(String name) {
    return NodejsRequiredCoreModule.class
        .getClassLoader()
        .getResourceAsStream("core-modules/" + name + ".js");
  }

  private static final Map<String, File> names = HashMapFactory.make();

  public static NodejsRequiredCoreModule make(String name) throws IOException {
    if (!names.containsKey(name)) {
      java.nio.file.Path p = Files.createTempDirectory("nodejs");
      File f = new File(p.toFile(), name + ".js");
      f.deleteOnExit();
      p.toFile().deleteOnExit();
      names.put(name, f);
    }
    File file = names.get(name);
    try (InputStream module = getModule(name)) {
      TemporaryFile.streamToFile(file, module);
    }
    SourceFileModule sourceFileModule =
        CAstCallGraphUtil.makeSourceModule(file.toURI().toURL(), file.getName());
    return new NodejsRequiredCoreModule(file, sourceFileModule);
  }

  public static boolean isCoreModule(String name) {
    return CORE_MODULES.contains(name);
  }
}
